package org.xyf.gateway.filter;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import org.xyf.common.AjaxResult;
import org.xyf.common.constant.GlobalConstant;
import org.xyf.common.utils.JwtUtils;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.List;
import java.util.Objects;

/**
 * 鉴权过滤器,解析jwt并传递header
 */
@Component
public class AuthFilter implements GlobalFilter, Ordered {

    private static Logger logger = LoggerFactory.getLogger(AuthFilter.class);

    private static final List<String> WHITE_LIST = List.of("/user/login");

    private static final String WEBSOCKET_PATH = "/im/connect";

    @Resource
    private ObjectMapper objectMapper;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        logTraceparentHeader(request);//测试打印请求头
        String path = request.getPath().value();
        if(WHITE_LIST.contains(path)){
            return chain.filter(exchange);
        }
        List<String> jwtList = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
        if(Objects.isNull(jwtList) || jwtList.isEmpty()){
            //响应401状态码
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return writeErrMsg(response);
        }
        logger.info("开始校验token......");
        String userId = JwtUtils.checkJwtAndGetSub(jwtList.get(0));
        if(WEBSOCKET_PATH.equals(path)){ //websocket则拼接为query参数
            ServerHttpRequest newReq = this.addQueryParam(GlobalConstant.USER_ID_HEADER, userId, request);
            return chain.filter(exchange.mutate().request(newReq).build());
        } else {
            request.mutate().header(GlobalConstant.USER_ID_HEADER,userId);
        }

        return chain.filter(exchange);
    }


    @Override
    public int getOrder() {
        return -1;
    }

    private Mono<Void> writeErrMsg(ServerHttpResponse response) {
        AjaxResult<Void> resBody = AjaxResult.unauthorized("未登录或jwt已过期!");
        try {
            byte[] bytes = objectMapper.writeValueAsBytes(resBody);
            DataBuffer buffer = response.bufferFactory().wrap(bytes);
            return response.writeWith(Mono.just(buffer));
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    private ServerHttpRequest addQueryParam(String key,String value,ServerHttpRequest request) {
        URI uri = UriComponentsBuilder.fromUri(request.getURI())
                .queryParam(key, value)
                .build()
                .toUri();
        return request.mutate()
                .uri(uri)
                .build();
    }

    /**
     * 打印前端传递的traceparent这个请求头
     * @param request
     */
    private void logTraceparentHeader(ServerHttpRequest request) {
        List<String> list = request.getHeaders().get("traceparent");
        if(Objects.isNull(list) || list.isEmpty()){
            logger.info("前端没有传递请求头-traceparent");
        } else {
            logger.info("traceparent is : {}",list.get(0));
        }
    }
}
